package org.ithasu.tools.data;

import java.util.ArrayList;
import java.util.Iterator;

import org.ithasu.tools.CollectionTools;
import org.ithasu.tools.net.JSONTools;
import org.ithasu.tools.net.JSONTools.JSONContext;
import org.ithasu.tools.net.JSONTools.JSONEntity;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

public class EList<E extends Entity> implements JSONEntity {

	private final static String JSON_PROPERTY_PROVIDER = "provider";
	private final static String JSON_PROPERTY_IDS = "ids";

	private EntityProvider<E> provider;
	private final ArrayList<Long> ids = new ArrayList<Long>();

	@SafeVarargs
	public EList(EntityProvider<E> provider, E... elements) {
		this.provider = provider;
		if (!CollectionTools.isEmpty(elements)) {
			for (E e : elements) {
				if (e != null) {
					this.ids.add(e.getId());
				}
			}
		}
	}

	// -- Properties ----------------------------------------

	public EntityProvider<E> getProvider() {
		return provider;
	}

	public ArrayList<Long> getIds() {
		return ids;
	}

	// -- Access ----------------------------------------

	public E get(int index) {
		if (index < 0 || index >= ids.size()) {
			return null;
		} else {
			return provider.getEntityById(ids.get(index));
		}
	}

	public ArrayList<E> getAll() {
		ArrayList<E> res = new ArrayList<E>();
		for (Long id : ids) {
			res.add(id == null ? null : provider.getEntityById(id));
		}
		return res;
	}

	// -- Modify ----------------------------------------

	public void add(E entity) {
		ids.add(entity == null ? null : entity.getId());
	}

	public void add(long id) {
		ids.add(id);
	}

	public void remove(E entity) {
		ids.remove(entity == null ? null : entity.getId());
	}

	public void remove(long id) {
		ids.remove(new Long(id));
	}

	public void clear() {
		ids.clear();
	}

	// -- Tools ----------------------------------------

	public void clearInvalid() {
		Iterator<Long> it = ids.iterator();
		while (it.hasNext()) {
			if (!EntityTools.isValid(provider, it.next())) {
				it.remove();
			}
		}
	}

	@Override
	public String toString() {
		return CollectionTools.toString(ids);
	}

	// -- JSON ----------------------------------------

	@SuppressWarnings("unchecked")
	@Override
	public void parseJSON(JSONContext context, JSONObject o) {
		clear();

		if (o == null) {
			return;
		}

		String providerId = JSONTools.getProperty(String.class, o, JSON_PROPERTY_PROVIDER);
		if (providerId == null) {
			return;
		}
		EntityProvider<?> provider = context.getEntityProvider(providerId);
		if (provider == null) {
			return;
		}
		this.provider = (EntityProvider<E>) provider;

		JSONArray values = JSONTools.getProperty(JSONArray.class, o, JSON_PROPERTY_IDS);
		for (Object v : values) {
			Long id = JSONTools.safeCast(Long.class, v);
			if (id == null) {
				// Error
				continue;
			}
			this.ids.add(id < 0 ? null : id);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public JSONObject toJSON(JSONContext context) {
		JSONObject o = new JSONObject();
		o.put(JSON_PROPERTY_PROVIDER, context.getEntityProviderId(provider));
		o.put(JSON_PROPERTY_IDS, ids);
		return o;
	}

}
